package catchnthrow;

import java.awt.*;
import java.awt.event.*;
import java.text.DateFormat;
import java.util.Calendar;

import javax.swing.*;

import se.lth.control.*;
import se.lth.control.plot.*;

public class Opcom {

	private int priority;
	private static final double eps = 0.000001;
	
	//UI Components
	private JFrame mainFrame;
	private JTabbedPane tabbedPanel;
	private BoxPanel guiPanel, plotterPanel, mainControlPanel, beamControlPanel, beamAndBallControlPanel, throwControlPanel; 
	
	private JScrollPane output;
	private JEditorPane outputTextArea;
	private String outputText;
	
	private PlotterPanel ballPlotter, anglePlotter;
	
	//Main Control Components
	private JButton runStep, stop, reset;
	
	//Beam Control Parameters Components
	private JButton beamApplyButton;
	private DoubleField beamParKField = new DoubleField(5,3);
	private DoubleField beamParTiField = new DoubleField(5,3);
	private DoubleField beamParTrField = new DoubleField(5,3);
	private DoubleField beamParNField = new DoubleField(5,3);
	private DoubleField beamParTdField = new DoubleField(5,3);
	private DoubleField beamParBetaField = new DoubleField(5,3);
	private DoubleField beamParHField = new DoubleField(5,3);
	
	//Beam And Ball Parameter Components
	boolean hChanged = false;
	private DoubleField innerParKField = new DoubleField(5,3);
	private DoubleField innerParTiField = new DoubleField(5,3);
	private DoubleField innerParTrField = new DoubleField(5,3);
	private DoubleField innerParTdField = new DoubleField(5,3);
	private DoubleField innerParNField = new DoubleField(5,3);
	private DoubleField innerParBetaField = new DoubleField(5,3);
	private DoubleField innerParHField = new DoubleField(5,3);
	private JButton innerApplyButton;

	private DoubleField outerParKField = new DoubleField(5,3);
	private DoubleField outerParTiField = new DoubleField(5,3);
	private DoubleField outerParTdField = new DoubleField(5,3);
	private DoubleField outerParTrField = new DoubleField(5,3);
	private DoubleField outerParNField = new DoubleField(5,3);
	private DoubleField outerParBetaField = new DoubleField(5,3);
	private DoubleField outerParHField = new DoubleField(5,3);
	private JButton outerApplyButton;
	
	//Throw Control Components
	private DoubleField throwParBallPos1 = new DoubleField(5,3);
	private DoubleField throwParBeam1Pos1 = new DoubleField(5,3);
	private DoubleField throwParBeam2Pos1 = new DoubleField(5,3);
	private DoubleField throwParWait1 = new DoubleField(5,3);
	private DoubleField throwParWaitEnd1 = new DoubleField(5,3);
	
	private DoubleField throwParBallPos2 = new DoubleField(5,3);
	private DoubleField throwParBeam1Pos2 = new DoubleField(5,3);
	private DoubleField throwParBeam2Pos2 = new DoubleField(5,3);
	private DoubleField throwParWait2 = new DoubleField(5,3);
	private DoubleField throwParWaitEnd2 = new DoubleField(5,3);
	
	private DoubleField throwParBallPos3 = new DoubleField(5,3);
	private DoubleField throwParBeam1Pos3 = new DoubleField(5,3);
	private DoubleField throwParBeam2Pos3 = new DoubleField(5,3);
	private DoubleField throwParWait3 = new DoubleField(5,3);
	private DoubleField throwParWaitEnd3 = new DoubleField(5,3);
	private JButton throwApply;
	
	//Parameter class Components
	private SM stateMachine;
	private PIDParameters beamPar; //Parameters of Beam Control
	
	private PIDParameters innerBallPar; //Parameter of inner control loop for cascaded control
	private PIDParameters outerBallPar; //Parameter of outer control loop for cascaded control
	private ThrowParameters[] throwPar;
	
	public Opcom(int PlotterPri, SM sm) {
		priority = PlotterPri;
		this.stateMachine = sm;
	}
	
	public void initializeUI() {
		outputText = new String();
		
		throwPar = stateMachine.thr.getBallParameters();
		
		beamPar = new PIDParameters();
		beamPar.K = 4.5;
		beamPar.Ti = 7.0;
		beamPar.Tr = 10.0;
		beamPar.Td = 0.3;
		beamPar.N = 7.0;
		beamPar.Beta = 1.0;
		beamPar.H = 0.01;
		beamPar.integratorOn = true;
		stateMachine.beam.setParameters(beamPar);
		
		innerBallPar = new PIDParameters();
		innerBallPar.K = 4.5;
		innerBallPar.Ti = 7.0;
		innerBallPar.Tr = 10.0;
		innerBallPar.Td = 0.3;
		innerBallPar.N = 7.0;
		innerBallPar.Beta = 1.0;
		innerBallPar.H = 0.01;
		innerBallPar.integratorOn = true;
		stateMachine.bb.setInnerParameters(innerBallPar);

		outerBallPar = new PIDParameters();
		outerBallPar.K = -0.2;
		outerBallPar.Ti = 10.0;
		outerBallPar.Tr = 10.0;
		outerBallPar.Td = 0.9;
		outerBallPar.Beta = 1.0;
		outerBallPar.H = 0.01;
		outerBallPar.N = 10.0;
		outerBallPar.integratorOn = true;
		stateMachine.bb.setOuterParameters(outerBallPar);
		
		//Building actually Frame
		mainFrame = new JFrame("Catch and Throw Project - Real-Time-Systems 2008");
		
		//Building Tabs
		initPlotterPanel();
		initMainControlPanel();
		initBeamControlPanel();
		initBeamAndBallControlPanel();
		initThrowControlPanel();
		
		//Setting up TabbedPanel
		tabbedPanel = new JTabbedPane();
		tabbedPanel.add("Main", mainControlPanel);
		tabbedPanel.add("Beam", beamControlPanel);
		tabbedPanel.add("B&B", beamAndBallControlPanel);
		tabbedPanel.add("Throw", throwControlPanel);
		
		guiPanel = new BoxPanel(BoxPanel.HORIZONTAL);
		guiPanel.add(tabbedPanel);
		guiPanel.addFixed(10);
		guiPanel.add(plotterPanel);
		
		
		// WindowListener that exits the system if the main window is closed.
		mainFrame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				ballPlotter.stopThread();
				anglePlotter.stopThread();
				//TODO Controller stoppen
				stateMachine.beam.shutDown();
				stateMachine.bb.shutDown();
				System.exit(0);
			}
		});
		
		// Set guiPanel to be content pane of the frame.
		mainFrame.getContentPane().add(guiPanel, BorderLayout.CENTER);

		// Pack the components of the window.
		mainFrame.pack();

		// Position the main window at the screen center.
		Dimension sd = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension fd = mainFrame.getSize();
		mainFrame.setLocation((sd.width-fd.width)/2, (sd.height-fd.height)/2);

		// Make the window visible.
		mainFrame.setVisible(true);
		
		anglePlotter.start();
		ballPlotter.start();
	}

	private void initPlotterPanel() {
		//Setting up plotting area
		plotterPanel = new BoxPanel(BoxPanel.VERTICAL);
		
		ballPlotter = new PlotterPanel(3, priority);
		ballPlotter.setName("BallPlotter");
		ballPlotter.setYAxis(20, -10, 2, 2);
		ballPlotter.setXAxis(10, 5, 5);
		ballPlotter.setUpdateFreq(10);
		
		anglePlotter = new PlotterPanel(3, priority);
		anglePlotter.setName("AnglePlotter");
		anglePlotter.setYAxis(20, -10, 2, 2);
		anglePlotter.setXAxis(10, 5, 5);
		anglePlotter.setUpdateFreq(10);
		
		plotterPanel.add(ballPlotter);
		plotterPanel.addFixed(10);
		plotterPanel.add(anglePlotter);
	}

	private void initMainControlPanel() {
		//Setting up Output
		outputTextArea = new JEditorPane();
		outputTextArea.setContentType("text/html");
		output = new JScrollPane(outputTextArea);
		
		//Setting up ButtonBar
		runStep = new JButton("Run");
		runStep.addActionListener(new RunStepAction());
		stop = new JButton("Stop");
		stop.setEnabled(false);
		stop.addActionListener(new StopAction());
		reset = new JButton("Reset");
		reset.addActionListener(new ResetAction());
		
		BoxPanel buttonBar = new BoxPanel(BoxPanel.HORIZONTAL);
		buttonBar.add(runStep);
		buttonBar.addFixed(3);
		buttonBar.add(stop);
		buttonBar.addFixed(3);
		buttonBar.add(reset);
				
		//Setting up mainTab
		mainControlPanel = new BoxPanel(BoxPanel.VERTICAL);
		mainControlPanel.setBorder(BorderFactory.createTitledBorder("Main Control"));
		mainControlPanel.add(output);
		mainControlPanel.addFixed(10);
		mainControlPanel.add(buttonBar);
	}

	private void initBeamControlPanel() {
		BoxPanel beamParameterPanel = new BoxPanel(BoxPanel.HORIZONTAL);
		
		JPanel beamParLabelPanel = new JPanel();
		beamParLabelPanel.setLayout(new GridLayout(0,1));
		beamParLabelPanel.add(new JLabel("K: "));
		beamParLabelPanel.add(new JLabel("Ti: "));
		beamParLabelPanel.add(new JLabel("Td: "));
		beamParLabelPanel.add(new JLabel("N: "));
		beamParLabelPanel.add(new JLabel("Tr: "));
		beamParLabelPanel.add(new JLabel("Beta: "));
		beamParLabelPanel.add(new JLabel("h: "));
		
		JPanel beamParFieldPanel = new JPanel();
		beamParFieldPanel.setLayout(new GridLayout(0,1));
		beamParFieldPanel.add(beamParKField); 
		beamParFieldPanel.add(beamParTiField);
		beamParFieldPanel.add(beamParTdField);
		beamParFieldPanel.add(beamParNField);
		beamParFieldPanel.add(beamParTrField);
		beamParFieldPanel.add(beamParBetaField);
		beamParFieldPanel.add(beamParHField);
		
		beamParKField.setValue(beamPar.K);
		beamParTiField.setValue(beamPar.Ti);
		beamParTiField.setMinimum(-eps);
		beamParTrField.setValue(beamPar.Tr);
		beamParTrField.setMinimum(-eps);
		beamParTdField.setValue(beamPar.Td);
		beamParTdField.setMinimum(-eps);
		beamParNField.setValue(beamPar.N);
		beamParBetaField.setValue(beamPar.Beta);
		beamParBetaField.setMinimum(-eps);
		beamParHField.setValue(beamPar.H);
		beamParHField.setMinimum(-eps);
		
		// Add action listeners to the fields
		beamParKField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.K = beamParKField.getValue();
				beamApplyButton.setEnabled(true);
			}
		});
		beamParTiField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.Ti = beamParTiField.getValue();
				if (beamPar.Ti < eps) {
					beamPar.integratorOn = false;
				}
				else {
					beamPar.integratorOn = true;
				}
				beamApplyButton.setEnabled(true);
			}
		});
		beamParTrField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.Tr = beamParTrField.getValue();
				beamApplyButton.setEnabled(true);
			}
		});
		beamParTdField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.Td = beamParTdField.getValue();
				beamApplyButton.setEnabled(true);
			}
		});
		beamParNField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.N = beamParNField.getValue();
				beamApplyButton.setEnabled(true);
			}
		});

		beamParBetaField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.Beta = beamParBetaField.getValue();
				beamApplyButton.setEnabled(true);
			}
		});
		beamParHField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				beamPar.H = beamParHField.getValue();
				beamApplyButton.setEnabled(true);
			}
		});

		// Create apply button and action listener.
		beamApplyButton = new JButton("Apply");
		beamApplyButton.setEnabled(false);
		beamApplyButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setOutput("Beam Parameters applied");
				stateMachine.beam.setParameters(beamPar);
				beamApplyButton.setEnabled(false);
			}
		});
		
		beamParameterPanel.add(beamParLabelPanel);
		beamParameterPanel.addGlue();
		beamParameterPanel.add(beamParFieldPanel);
		
		beamControlPanel = new BoxPanel(BoxPanel.VERTICAL);
		beamControlPanel.setBorder(BorderFactory.createTitledBorder("Beam Control Parameters"));
		beamControlPanel.add(beamParameterPanel);
		beamControlPanel.addFixed(10);
		beamControlPanel.add(beamApplyButton);
	}

	private void initBeamAndBallControlPanel() {
		
		// Create panels for the parameter fields and labels, add labels and fields 
		BoxPanel innerParPanel = new BoxPanel(BoxPanel.HORIZONTAL);
		
		JPanel innerParLabelPanel = new JPanel();
		innerParLabelPanel.setLayout(new GridLayout(0,1));
		innerParLabelPanel.add(new JLabel("K: "));
		innerParLabelPanel.add(new JLabel("Ti: "));
		innerParLabelPanel.add(new JLabel("Td: "));
		innerParLabelPanel.add(new JLabel("N: "));
		innerParLabelPanel.add(new JLabel("Tr: "));
		innerParLabelPanel.add(new JLabel("Beta: "));
		innerParLabelPanel.add(new JLabel("h: "));
		
		JPanel innerParFieldPanel = new JPanel();
		innerParFieldPanel.setLayout(new GridLayout(0,1));
		innerParFieldPanel.add(innerParKField); 
		innerParFieldPanel.add(innerParTiField);

		innerParFieldPanel.add(innerParTdField);
		innerParFieldPanel.add(innerParNField);
		
		innerParFieldPanel.add(innerParTrField);
		innerParFieldPanel.add(innerParBetaField);
		innerParFieldPanel.add(innerParHField);

		// Set initial parameter values of the fields
		innerParKField.setValue(innerBallPar.K);
		innerParTiField.setValue(innerBallPar.Ti);
		innerParTiField.setMinimum(-eps);
		innerParTrField.setValue(innerBallPar.Tr);
		innerParTrField.setMinimum(-eps);
		innerParTdField.setValue(innerBallPar.Td);

		innerParNField.setValue(innerBallPar.N);
		innerParNField.setMinimum(-eps);
		innerParBetaField.setValue(innerBallPar.Beta);
		innerParBetaField.setMinimum(-eps);
		innerParHField.setValue(innerBallPar.H);
		innerParHField.setMinimum(-eps);

		// Add action listeners to the fields
		innerParKField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.K = innerParKField.getValue();
				innerApplyButton.setEnabled(true);
			}
		});
		innerParTiField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.Ti = innerParTiField.getValue();
				if (innerBallPar.Ti < eps) {
					innerBallPar.integratorOn = false;
				}
				else {
					innerBallPar.integratorOn = true;
				}
				innerApplyButton.setEnabled(true);
			}
		});
		innerParTrField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.Tr = innerParTrField.getValue();
				innerApplyButton.setEnabled(true);
			}
		});

		innerParTdField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.Td = innerParTdField.getValue();
				innerApplyButton.setEnabled(true);
			}
		});

		innerParNField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.N = innerParNField.getValue();
				innerApplyButton.setEnabled(true);
			}
		});
		innerParBetaField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.Beta = innerParBetaField.getValue();
				innerApplyButton.setEnabled(true);
			}
		});
		innerParHField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				innerBallPar.H = innerParHField.getValue();
				outerBallPar.H = innerBallPar.H;
				outerParHField.setValue(innerBallPar.H);
				innerApplyButton.setEnabled(true);
				hChanged = true;
			}
		});

		// Add label and field panels to parameter panel
		innerParPanel.add(innerParLabelPanel);
		innerParPanel.addGlue();
		innerParPanel.add(innerParFieldPanel);
		innerParPanel.addFixed(10);

		// Create apply button and action listener.
		innerApplyButton = new JButton("Apply");
		innerApplyButton.setEnabled(false);
		innerApplyButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setOutput("Inner Parameters applied");
				stateMachine.bb.setInnerParameters(innerBallPar);
				if (hChanged) {
					stateMachine.bb.setOuterParameters(outerBallPar);
				}	
				hChanged = false;
				innerApplyButton.setEnabled(false);
			}
		});

		// Create panel with border to hold apply button and parameter panel
		BoxPanel innerParButtonPanel = new BoxPanel(BoxPanel.VERTICAL);
		innerParButtonPanel.setBorder(BorderFactory.createTitledBorder("Inner Parameters"));
		innerParButtonPanel.addFixed(10);
		innerParButtonPanel.add(innerParPanel);
		innerParButtonPanel.addFixed(10);
		innerParButtonPanel.add(innerApplyButton);

		// The same as above for the outer parameters
		BoxPanel outerParPanel = new BoxPanel(BoxPanel.HORIZONTAL);
		
		JPanel outerParLabelPanel = new JPanel();
		outerParLabelPanel.setLayout(new GridLayout(0,1));
		outerParLabelPanel.add(new JLabel("K: "));
		outerParLabelPanel.add(new JLabel("Ti: "));
		outerParLabelPanel.add(new JLabel("Td: "));
		outerParLabelPanel.add(new JLabel("N: "));
		outerParLabelPanel.add(new JLabel("Tr: "));
		outerParLabelPanel.add(new JLabel("Beta: "));
		outerParLabelPanel.add(new JLabel("h: "));

		JPanel outerParFieldPanel = new JPanel();
		outerParFieldPanel.setLayout(new GridLayout(0,1));
		outerParFieldPanel.add(outerParKField); 
		outerParFieldPanel.add(outerParTiField);
		outerParFieldPanel.add(outerParTdField);
		outerParFieldPanel.add(outerParNField);
		outerParFieldPanel.add(outerParTrField);
		outerParFieldPanel.add(outerParBetaField);
		outerParFieldPanel.add(outerParHField);
		outerParKField.setValue(outerBallPar.K);
		outerParTiField.setValue(outerBallPar.Ti);
		outerParTiField.setMinimum(-eps);
		outerParTdField.setValue(outerBallPar.Td);
		outerParTdField.setMinimum(-eps);
		outerParNField.setValue(outerBallPar.N);
		outerParTrField.setValue(outerBallPar.Tr);
		outerParBetaField.setValue(outerBallPar.Beta);
		outerParBetaField.setMinimum(-eps);
		outerParHField.setValue(outerBallPar.H);
		outerParHField.setMinimum(-eps);
		outerParKField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.K = outerParKField.getValue();
				outerApplyButton.setEnabled(true);
			}
		});
		outerParTiField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.Ti = outerParTiField.getValue();
				if (outerBallPar.Ti < eps) {
					outerBallPar.integratorOn = false;
				}
				else {
					outerBallPar.integratorOn = true;
				}
				outerApplyButton.setEnabled(true);
			}
		});
		outerParTdField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.Td = outerParTdField.getValue();
				outerApplyButton.setEnabled(true);
			}
		});
		outerParNField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.N = outerParNField.getValue();
				outerApplyButton.setEnabled(true);
			}
		});
		outerParTrField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.Tr = outerParTrField.getValue();
				outerApplyButton.setEnabled(true);
			}
		});
		outerParBetaField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.Beta = outerParBetaField.getValue();
				outerApplyButton.setEnabled(true);
			}
		});
		outerParHField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				outerBallPar.H = outerParHField.getValue();
				innerBallPar.H = outerBallPar.H;
				innerParHField.setValue(outerBallPar.H);
				outerApplyButton.setEnabled(true);
				hChanged = true;
			}
		});

		outerParPanel.add(outerParLabelPanel);
		outerParPanel.addGlue();
		outerParPanel.add(outerParFieldPanel);
		outerParPanel.addFixed(10);

		outerApplyButton = new JButton("Apply");
		outerApplyButton.setEnabled(false);
		outerApplyButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setOutput("Outer Parameters applied");
				stateMachine.bb.setOuterParameters(outerBallPar);
				if (hChanged) {
					stateMachine.bb.setInnerParameters(innerBallPar);
				}	
				hChanged = false;
				outerApplyButton.setEnabled(false);
			}
		});

		BoxPanel outerParButtonPanel = new BoxPanel(BoxPanel.VERTICAL);
		outerParButtonPanel.setBorder(BorderFactory.createTitledBorder("Outer Parameters"));
		outerParButtonPanel.addFixed(10);
		outerParButtonPanel.add(outerParPanel);
		outerParButtonPanel.addFixed(10);
		outerParButtonPanel.add(outerApplyButton);

		// Create panel for parameter fields, labels and apply buttons
		beamAndBallControlPanel = new BoxPanel(BoxPanel.HORIZONTAL);
		beamAndBallControlPanel.setBorder(BorderFactory.createTitledBorder("Beam and Ball Control"));
		beamAndBallControlPanel.add(innerParButtonPanel);
		beamAndBallControlPanel.addGlue();
		beamAndBallControlPanel.add(outerParButtonPanel);
	}
	
	private void initThrowControlPanel() {
		throwApply = new JButton("Apply");
		throwApply.setEnabled(false);
		
		JPanel throwValPanel0 = new JPanel();
		throwValPanel0.setLayout(new GridLayout(0,1));
		throwValPanel0.add(new JLabel("BallSize"));
		throwValPanel0.add(new JLabel("BallPosition"));
		throwValPanel0.add(new JLabel("BeamPosition 1"));
		throwValPanel0.add(new JLabel("BeamPosition 2"));
		throwValPanel0.add(new JLabel("WaitTime"));
		throwValPanel0.add(new JLabel("WaitTimeEnd"));
		
		JPanel throwValPanel1 = new JPanel();
		throwValPanel1.setLayout(new GridLayout(0,1));
		throwValPanel1.add(new JLabel("S"));
		throwValPanel1.add(throwParBallPos1);
		throwValPanel1.add(throwParBeam1Pos1);
		throwValPanel1.add(throwParBeam2Pos1);
		throwValPanel1.add(throwParWait1);
		throwValPanel1.add(throwParWaitEnd1);
		
		throwParBallPos1.setValue(stateMachine.thr.getBallParameters()[0].BallPosition);
		throwParBeam1Pos1.setValue(stateMachine.thr.getBallParameters()[0].BeamPos1);
		throwParBeam2Pos1.setValue(stateMachine.thr.getBallParameters()[0].BeamPos2);
		throwParWait1.setValue(stateMachine.thr.getBallParameters()[0].WaitTime);
		throwParWaitEnd1.setValue(stateMachine.thr.getBallParameters()[0].WaitTimeEnd);

		throwParBallPos1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[0].BallPosition = throwParBallPos1.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParBeam1Pos1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[0].BeamPos1 = throwParBeam1Pos1.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParBeam2Pos1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[0].BeamPos2 = throwParBeam2Pos1.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParWait1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[0].WaitTime = Double.doubleToLongBits(throwParWait1.getValue());
				throwApply.setEnabled(true);
			}
		});
		throwParWaitEnd1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[0].WaitTimeEnd = Double.doubleToLongBits(throwParWaitEnd1.getValue());
				throwApply.setEnabled(true);
			}
		});
		
		JPanel throwValPanel2 = new JPanel();
		throwValPanel2.setLayout(new GridLayout(0,1));
		throwValPanel2.add(new JLabel("M"));
		throwValPanel2.add(throwParBallPos2);
		throwValPanel2.add(throwParBeam1Pos2);
		throwValPanel2.add(throwParBeam2Pos2);
		throwValPanel2.add(throwParWait2);
		throwValPanel2.add(throwParWaitEnd2);
		
		throwParBallPos2.setValue(stateMachine.thr.getBallParameters()[1].BallPosition);
		throwParBeam1Pos2.setValue(stateMachine.thr.getBallParameters()[1].BeamPos1);
		throwParBeam2Pos2.setValue(stateMachine.thr.getBallParameters()[1].BeamPos2);
		throwParWait2.setValue(stateMachine.thr.getBallParameters()[1].WaitTime);
		throwParWaitEnd2.setValue(stateMachine.thr.getBallParameters()[1].WaitTimeEnd);
		
		throwParBallPos2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[1].BallPosition = throwParBallPos2.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParBeam1Pos2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[1].BeamPos1 = throwParBeam1Pos2.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParBeam2Pos2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[1].BeamPos2 = throwParBeam2Pos2.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParWait2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[1].WaitTime = Double.doubleToLongBits(throwParWait2.getValue());
				throwApply.setEnabled(true);
			}
		});
		throwParWaitEnd2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[1].WaitTimeEnd = Double.doubleToLongBits(throwParWaitEnd2.getValue());
				throwApply.setEnabled(true);
			}
		});
		
		JPanel throwValPanel3 = new JPanel();
		throwValPanel3.setLayout(new GridLayout(0,1));
		throwValPanel3.add(new JLabel("XL"));
		throwValPanel3.add(throwParBallPos3);
		throwValPanel3.add(throwParBeam1Pos3);
		throwValPanel3.add(throwParBeam2Pos3);
		throwValPanel3.add(throwParWait3);
		throwValPanel3.add(throwParWaitEnd3);
		
		throwParBallPos3.setValue(stateMachine.thr.getBallParameters()[2].BallPosition);
		throwParBeam1Pos3.setValue(stateMachine.thr.getBallParameters()[2].BeamPos1);
		throwParBeam2Pos3.setValue(stateMachine.thr.getBallParameters()[2].BeamPos2);
		throwParWait3.setValue(stateMachine.thr.getBallParameters()[2].WaitTime);
		throwParWaitEnd3.setValue(stateMachine.thr.getBallParameters()[2].WaitTimeEnd);
		
		throwParBallPos3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[2].BallPosition = throwParBallPos3.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParBeam1Pos3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[2].BeamPos1 = throwParBeam1Pos3.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParBeam2Pos3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[2].BeamPos2 = throwParBeam2Pos3.getValue();
				throwApply.setEnabled(true);
			}
		});
		throwParWait3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[2].WaitTime = Double.doubleToLongBits(throwParWait3.getValue());
				throwApply.setEnabled(true);
			}
		});
		throwParWaitEnd3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				throwPar[2].WaitTimeEnd = Double.doubleToLongBits(throwParWaitEnd3.getValue());
				throwApply.setEnabled(true);
			}
		});
		
		BoxPanel throwParPanel = new BoxPanel(BoxPanel.HORIZONTAL);
		throwParPanel.add(throwValPanel0);
		throwParPanel.addGlue();
		throwParPanel.add(throwValPanel1);
		throwParPanel.addGlue();
		throwParPanel.add(throwValPanel2);
		throwParPanel.addGlue();
		throwParPanel.add(throwValPanel3);
		
		throwApply.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				stateMachine.thr.setBallParam(throwPar);
				throwApply.setEnabled(false);
				setOutput("Throw Parameter changed");
			}
		});
		
		throwControlPanel = new BoxPanel(BoxPanel.VERTICAL);
		throwControlPanel.setBorder(BorderFactory.createTitledBorder("Throw Parameters"));
		throwControlPanel.add(throwParPanel);
		throwControlPanel.addFixed(10);
		throwControlPanel.add(throwApply);
	}
	/**
	 * Method to output plain text
	 * @param line
	 */
	public void setOutput(String line) {
		Calendar cal = Calendar.getInstance();
	    DateFormat formater = DateFormat.getTimeInstance(DateFormat.MEDIUM);
		String head = new String("&lt;" + formater.format(cal.getTime()) + "&gt; ");
		
		if (outputText.length() == 0) {
			outputText = head + line;
		} else {
			outputText = head + line + "<br>" + outputText;
		}
		outputTextArea.setText(outputText);
	}
	
	/**
	 * Method to highlight output text in the specified html color and bold. <br>
	 * e.g. <br>
	 * RED = #800000 <br>
	 * GREEN = #008000
	 * @param text
	 * @param htmlColor
	 */
	public void setOutput(String line, String htmlColor) {
		Calendar cal = Calendar.getInstance();
	    DateFormat formater = DateFormat.getTimeInstance(DateFormat.MEDIUM);
		String head = new String("&lt;" + formater.format(cal.getTime()) + "&gt; ");
		String startTag = new String("<font color=\"" + htmlColor + "\"><b>");
		String endTag = new String("</b></font>");
		
		if (outputText.length() == 0) {
			outputText = startTag + head + line + endTag;
		} else {
			outputText = startTag + head + line + endTag + "<br>" + outputText;
		}
		outputTextArea.setText(outputText);
	}
	
	private void setRunning(boolean running) {
		stop.setEnabled(running);
		runStep.setEnabled(!running);
	}
	
	public synchronized void putAngleDataPoint(PlotData pd) {
		anglePlotter.putData(pd.x, pd.ref, pd.y, pd.u);
	}
	
	public synchronized void putBallDataPoint(PlotData pd) {
		ballPlotter.putData(pd.x, pd.ref, pd.y, pd.u);
	}
	
	private class RunStepAction implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent arg0) {
			setOutput("Run Statemachine...");
			stateMachine.SM_start();
			setRunning(true);
		}
	}
	
	private class StopAction implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent arg0) {
			setOutput("Stop Statemachine...");
			stateMachine.SM_pause();
			setRunning(false);
		}
	}
	
	private class ResetAction implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent arg0) {
			setOutput("Reseting all values...");
			stateMachine.SM_reset();
		}
	}
	
}
